package com.jeasonzhao.commons.parser.lex;

public abstract class LexTokenizer
{
    public final static char END = (char) 0;
    //region Members
    private String m_strInitStatement = null;
    private char[] m_charStatementArray = null;
    private int m_nLengthOfStatement = 0;
    private int m_nCurrentPosition = 0;
    private int m_nCurrentRowIndex = 0;
    private int m_nRowsCount = 0;
    private int m_nCurrentColumnIndex = 0;

    //region CTor
    public LexTokenizer()
    {
    }

    public LexTokenizer(String strStatement)
    {
        m_strInitStatement = strStatement;
        reload();
    }

    public void reload()
    {
        m_strInitStatement = null == m_strInitStatement ? null : m_strInitStatement + " ";
        m_charStatementArray = null == m_strInitStatement ? null : m_strInitStatement.toCharArray();
        m_nLengthOfStatement = m_strInitStatement == null ? 0 : m_charStatementArray.length;
        m_nCurrentPosition = 0;
        m_nCurrentRowIndex = 0;
        m_nRowsCount = 0;
    }

    //region NavFun
    protected char peekPrev(int nPrevCount)
    {
        int n = m_nCurrentPosition - nPrevCount;
        return m_nCurrentPosition < 0
            || n < 0
            || n >= m_nLengthOfStatement ? END :
            m_charStatementArray[n];
    }

    protected char peekNext(int nNextCount)
    {
        int n = m_nCurrentPosition + nNextCount;
        return m_nCurrentPosition < 0
            || n < 0
            || n >= m_nLengthOfStatement ? END :
            m_charStatementArray[n];
    }

    protected boolean isNextStringMatchs(String str)
    {
        if(null == str)
        {
            return false;
        }
        else
        {
            String next = this.getNextString(str.length());
            return next != null && next.equals(str);
        }
    }

    private String getNextString(int nNextCount)
    {
        return m_strInitStatement.substring(Math.max(0,m_nCurrentPosition),
                                            Math.min(m_nLengthOfStatement - 1,m_nCurrentPosition + nNextCount));
    }

    protected String getPrevString(int nPrevCount)
    {
        return m_strInitStatement.substring(Math.max(0,m_nCurrentPosition - nPrevCount),
                                            Math.min(m_nLengthOfStatement - 1,m_nCurrentPosition));
    }

    protected char peekNext()
    {
        return peekNext(1);
    }

    protected char peekPrev()
    {
        return peekPrev(1);
    }

    protected char current()
    {
        return m_nCurrentPosition < 0
            || m_nCurrentPosition >= m_nLengthOfStatement ? END :
            m_charStatementArray[m_nCurrentPosition];
    }

    protected final void backTo(int nPos)
    {
        m_nCurrentPosition = nPos;
        m_nCurrentPosition = Math.max(m_nCurrentPosition,0);
    }

    protected final char next(int nLength)
    {
        char c = current();
        for(int n = 0;n < nLength;n++)
        {
            //I have no confidence to my source code, so let's do this character by character.
            c = next();
        }
        return c;
    }

    protected final char next()
    {
        if(m_nCurrentPosition < 0)
        {
            return END;
        }
        m_nCurrentPosition++;
        m_nCurrentColumnIndex++;
        int nIndex = m_nCurrentPosition;
        char c = nIndex < 0 || nIndex >= m_nLengthOfStatement ? END : m_charStatementArray[nIndex];
        if(c == '\n')
        {
            m_nCurrentColumnIndex = 0;
            m_nCurrentRowIndex++;
            m_nRowsCount++;
        }
        return c;
    }

    protected LexToken createToken()
    {
        return LexToken.create(m_nCurrentPosition,m_nCurrentRowIndex,m_nCurrentColumnIndex);
    }

    protected int getCurrentColumnIndex()
    {
        return m_nCurrentColumnIndex;
    }

    protected int getCurrentPosition()
    {
        return m_nCurrentPosition;
    }

    protected int getCurrentRowIndex()
    {
        return m_nCurrentRowIndex;
    }

    protected int getLengthOfStatement()
    {
        return m_nLengthOfStatement;
    }

    public int getRowsCount()
    {
        return m_nRowsCount;
    }

    public void setInitStatement(String str)
    {
        m_strInitStatement = str;
        this.reload();
    }

    public String getInitStatement()
    {
        return m_strInitStatement;
    }

    public abstract LexToken nextToken()
        throws LexException;


} //end of class SqlStringTokenizer
